/*! 
 * jquery.ux.selectable - v 1.0.0 - http://jquery-ux.com/
 * Copyright (c) 2010 Michael Helgeson, Three Dub Media
 * Open Source MIT License - http://jquery-ux.com/license 
 */
// Created: 2009-09-01
// Updated: 2010-01-22
// REQUIRES: jquery 1.4+, jquery.ux, jquery.align, event.drag 2.0, event.drop 2.0

;(function( $ ){ // confine scope

$.ux( "selectable", { // Register the PLUGIN... and public methods...
	expose: "", // + enable disable destroy
	defaults:{
		find: null,
		not: null,
		classroot: "ux-selectable"
		},
	create: function( elem, opts ){
		// store args, extend the instance
		$.extend( this, { elem:elem, opts:opts });
		// store the jquery wrapped element, bind events
		this.$elem = $( elem ).bind("drag dragstart dragend select", $.proxy( this, "handler") );
		// bind drop events to the child targets
		this.$nodes = $([]);
		this.pending = [];
		this.selected = [];
		this.reset();
		},
	destroy: function(){
		// remove the events
		this.$elem.unbind("drag dragstart dragend select", $.proxy( this, "handler") );
		},
	disable: function(){
		
		},
	methods: {
		// rebuild/rebind drop node cache
		reset: function(){
			// remove any old nodes from storage
			this.$nodes.removeClass( this.uxid.substr(1) )
				.unbind( "drop dropstart dropend", $.proxy( this, "handler") );
			// find/filter new nodes
			this.$nodes = this.$elem
				.find( this.opts.find || '> *' )
				.not( this.opts.not || "" )
				.addClass( this.uxid.substr(1) )
				.bind( "drop dropstart dropend", $.proxy( this, "handler") );
			},
		// handle the interaction events
		handler: function( event, dd ){
			if ( this.disabled ) return;			
			switch ( event.type ){
				case "dragstart":
					if ( !event.shiftKey ) this.forget();
					this.pending = [];
					// manage the drop targets
					$.dropManage({
						filter: this.uxid,
						mode: "overlap",	
						multi: true
						});
					// return the proxy element
					return $('<div/>')
						.css({ position:'absolute', top:0, left:0 })
						.addClass( this.classify("selection") )
						.appendTo( document.body );
				case "drag":
					// update the proxy position
					$( dd.proxy ).css({
						top: Math.min( event.pageY, dd.startY ),
						left: Math.min( event.pageX, dd.startX ),
						height: Math.abs( event.pageY - dd.startY ),
						width: Math.abs( event.pageX - dd.startX )
						});
					break;
				case "dropstart":
					this.activate( dd.drop );
					break;
				case "dropend":
					this.deactivate( dd.drop );
					break;
				case "drop":
					this.select( dd.drop );
				case "dragend":	
					$( dd.proxy ).remove();
					break;
				case "click":
					this.forget();
					this.select();
					break;
				}
			},
		activate: function( node ){
			this.pending.push( node );
			$( node ).addClass( this.classify("active") );
			},
		deactivate: function( node ){
			$( node ).removeClass( this.classify("active") );
			this.pending = $.grep( this.pending, function( elem ){
				return ( node !== elem );
				});
			},
		select: function( nodes ){
			var self = this, $node;
			$( nodes ).each(function(){
				$node = $( this ).removeClass( self.classify("active") );
				if ( $node.is( self.uxid ) )
					self.selected.push( $node.addClass( self.classify("selected") )[0] );
				});
			this.publish("select", this.selected ); // "selectable:select"
			},
		forget: function( nodes ){
			var removed = [];
			nodes = $( nodes || this.selected )
				.removeClass( this.classify("selected") );
			// filter the selected list for the nodes arguments
			this.selected = $.grep( this.selected, function( elem ){
				for ( var i = 0; i<nodes.length; i++ )
					if ( elem == nodes[i] ){
						removed.push( elem );
						return false;
						}
				return true;
				});
			if ( removed.length )
				this.publish("deselect", removed ); // "deselectable:select"
			return this;
			}
		}
	});

})( jQuery ); // secure the $ jQuery alias